package com.whu.UVAProtocol;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.whu.aircraft.*;
import com.whu.util.ByteUtil;
import com.whu.util.CRC16Util;
import com.whu.util.JacksonUtil;
import io.netty.channel.*;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * @Description
 * @Author chengeng
 * @Date 2021/10/28 17:03
 **/
@Slf4j
public class UVAServerHandler extends SimpleChannelInboundHandler<UVAMessageProtocolType1_3> {


    //处理心跳检测事件的方法
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        //super.userEventTriggered(ctx, evt);
        IdleStateEvent event = (IdleStateEvent) evt;

        switch (event.state()){
            case READER_IDLE:
                log.info(ctx.channel().remoteAddress()+"发生超时事件");
                if(ctx.channel().attr(UVAServer.channel_key).get()!=null){
                    UVAConnection connection = UVAServer.uvaConnections.get(ctx.channel().attr(UVAServer.channel_key).get());
                    connection.timeoutCntIncrease();
                    if(connection.getTimeoutCnt()>=3){
                        log.info("与无人机:"+ctx.channel().attr(UVAServer.channel_key).get()+"通讯的超时次数超过3次，关闭该连接,将会话移到重连队列中");
                        if(ctx.channel()!=null) {
                            //UVAConnection connection = UVAServer.uvaConnections.get((ctx.channel().attr(UVAServer.channel_key).get()));
                            UVAServer.uvaConnections.remove((ctx.channel().attr(UVAServer.channel_key).get()),connection);
                            connection.setExpiredTime(LocalDateTime.now().plusMinutes(UVAServer.connectionMST));//设置过期时间,1分钟
                            //connection.getMsgCache().clear();//清空缓存数据
                            connection.setTimeoutCnt(0);//还原超时次数
                            connection.setChannel(null);//删除原channel
                            UVAServer.disconnections.put((ctx.channel().attr(UVAServer.channel_key).get()),connection);
                            log.warn(ctx.channel().remoteAddress()+ "断开连接,对应的连接已移入待重连会话队列...");
                        }
                        ctx.channel().close();
                    }
                }else{
                    log.error("未识别的socket,关闭");
                    ctx.channel().close();
                }
                break;
            default:
                break;
        }

    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        super.channelInactive(ctx);
        //log.info(ctx.channel().remoteAddress()+"触发channelInactive");
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        super.channelRegistered(ctx);
        log.info(ctx.channel().remoteAddress()+"注册");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        super.channelUnregistered(ctx);
        log.info(ctx.channel().remoteAddress()+"卸载");
        if(ctx.channel()!=null) {
            UVAConnection connection = UVAServer.uvaConnections.get((ctx.channel().attr(UVAServer.channel_key).get()));
            if(connection!=null) {
                UVAServer.uvaConnections.remove((ctx.channel().attr(UVAServer.channel_key).get()),connection);
                log.info(ctx.channel().remoteAddress()+"从连接队列中移除");
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        log.error("错误："+cause.toString());
    }

    /**
     * @Description ""
     * @Param [channelHandlerContext, msg]
     * @Return void
     * @Author chengeng
     * @Date 2021/11/26 10:03
     **/
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, UVAMessageProtocolType1_3 msg) throws Exception {
        //接收到数据并处理
        UVAMessageProtocolWrapper protocolWrapper = new UVAMessageProtocolWrapper(msg);
        if((!protocolWrapper.isValidMagicNumber())||(!protocolWrapper.checkCRC())
                ||(protocolWrapper.getDIR()!=0)){
            //约定字符有误、CRC校验消息发生错误或者DIR传输方向出错，进行处理，日志记录并发送错误控制信息
            log.info("报文有误,关闭连接");
            channelHandlerContext.channel().close();
        }else {
            //获取OP
            short op = protocolWrapper.getOP();
            //根据op类型进行处理
            opHandler(channelHandlerContext,op,protocolWrapper);
        }
    }
    /**
     * @Description:根据操作码对消息体进行解析并处理
     * @Param [op, wrapper]
     * @Return  void
     * @Author chengeng
     * @Date 2021/10/19 12:59
     **/
    public void opHandler(ChannelHandlerContext ctx,short op,UVAMessageProtocolWrapper wrapper) throws JsonProcessingException {
        switch (op){
            case ClientOPType.OP_CONNECTION_REQUEST://处理连接请求
                connectHandler(ctx,wrapper);
                break;
            case ClientOPType.OP_CLOSE_CONNECTION://处理关闭请求
                closeHandler(ctx,wrapper);
                break;
            case ClientOPType.OP_ROUTE_INFO_ACK:
                routeInfoHandler(ctx,wrapper);
                break;
            case ClientOPType.OP_REQUEST_SHOT_ACK:
                log.warn("未定义的报文！");
                break;
            case ClientOPType.OP_WARNING_INFO_ACK:
                log.warn("未定义的报文！");
                break;
            case ClientOPType.OP_SEND_PICTURE://传送图片
                pictureHandler(ctx,wrapper);
                break;
            case ClientOPType.OP_UPDATE_UVA_LOCATION://无人机位置更新
                locationHandler(ctx,wrapper);
                break;
            case ClientOPType.OP_8:
                log.warn("未定义的报文！");
                break;
            case ClientOPType.OP_TASK_FINISHED:
                taskFinHandler(ctx,wrapper);
                break;
            case ClientOPType.OP_TRACK_INFO:
                trackInfoHandler(ctx,wrapper);
                break;
            case ClientOPType.OP_11:
                log.warn("未定义的报文！");
                break;
            case ClientOPType.OP_12:
                log.warn("未定义的报文！");
                break;
            case ClientOPType.OP_13:
                log.warn("未定义的报文！");
                break;
            case ClientOPType.OP_14:
                log.warn("未定义的报文！");
                break;
            case ClientOPType.OP_15:
                log.warn("未定义的报文！");
                break;
            case ClientOPType.OP_16://测试发送给客户端
//                byte[] datas = new byte[7890];
//                for(int i=0;i<datas.length;i++){
//                    datas[i] = (byte) (i%5);
//                }
//                test(ctx,wrapper,datas);

                byte[] location = {0x01,0x23,0x45,0x67,
                                    0x02,0x34,0x56,0x78,
                                    (byte) 0xF3,0x45,0x67,(byte) 0x89};
                testControl(ctx, wrapper, (byte) 2,location);
                break;
            default:
                log.warn("未定义的报文！");
        }
    }

    private void testControl(ChannelHandlerContext ctx, UVAMessageProtocolWrapper wrapper, byte ctldata,byte[] loaction) {

        log.info("发送控制信息"+(int)ctldata);

        byte div = 0x00;
        byte op = ServerOPType.OP_16;
        byte controlProp = packControlProp(div,op);
        byte[] divs = {0,0,0,0};
        byte[] msg = new byte[loaction.length+1];
        msg[0] = ctldata;
        for(int i=0;i<loaction.length;i++){
            msg[i+1] = loaction[i];
        }
        UVAMessageProtocolType1_3 connectMsg = new UVAMessageProtocolType1_3.Builder()
                .setControlProp(controlProp)
                .setDivs(divs)
                .setMsgBodyLen((short) msg.length)
                .setMsgBody(msg)
                .setSerialNum((char) 0)
                .build();
        UVAMessageProtocolWrapper connectMsgWrapper = new UVAMessageProtocolWrapper(connectMsg);
        short crcCheckNum = CRC16Util.getCRC(connectMsgWrapper.protocol2Array0());
        connectMsg.setCrcCheckNum(crcCheckNum);
        ctx.writeAndFlush(connectMsg);
    }

    //测试发送给客户端
    private void test(ChannelHandlerContext ctx, UVAMessageProtocolWrapper wrapper, byte[] datas) {
        log.info("处理多包请求");
        int maxLen = 1024;
        List<byte[]> dataList = new ArrayList<>();
        for(int i=0;i<datas.length;){
            int len = Math.min(maxLen,datas.length-i);
            int itemp = i;
            byte[] temp = new byte[len];
            for(int j=0;j<len;j++){
                temp[j] = datas[itemp++];
            }
            dataList.add(temp);
            if(i+maxLen<datas.length) {
                i = i + maxLen;
            }else {
                break;
            }
        }
        short totalPckNum = (short) dataList.size();
        byte[] totalPckNumBytes = ByteUtil.getBytes(totalPckNum);
        for(int i=0;i<dataList.size();i++) {
            //发送连接ACK报文
            short index = (short) i;
            byte[] indexBytes = ByteUtil.getBytes(index);
            byte div = 0x01;
            byte op = ServerOPType.OP_16;
            byte controlProp = packControlProp(div, op);
            byte[] divs = {totalPckNumBytes[0], totalPckNumBytes[1],indexBytes[0], indexBytes[1] };
            byte[] msg = dataList.get(i);
            UVAMessageProtocolType1_3 testMsg = new UVAMessageProtocolType1_3.Builder()
                    .setControlProp(controlProp)
                    .setDivs(divs)
                    .setMsgBodyLen((short) msg.length)
                    .setMsgBody(msg)
                    .build();
            char serialNum = 0;
            if(i!=dataList.size()-1){
                UVAConnection connection = UVAServer.uvaConnections.get((int)(wrapper.getProtocolType1_3().getAddressProp()));
                serialNum = connection.getSerialNumForDIV();
                System.out.println();
            }else {
               serialNum = UVAServer.uvaConnections.get((int)(wrapper.getProtocolType1_3().getAddressProp())).getSerialNum();
            }
            testMsg.setSerialNum(serialNum);
            UVAMessageProtocolWrapper connectMsgWrapper = new UVAMessageProtocolWrapper(testMsg);
            short crcCheckNum = CRC16Util.getCRC(connectMsgWrapper.protocol2Array0());
            testMsg.setCrcCheckNum(crcCheckNum);
            log.info("发送流水号为"+(int)serialNum+"总包数为:"+totalPckNum+"序列为:"+i+"分包长度："+msg.length);
            log.info(testMsg.toString());
            ctx.writeAndFlush(testMsg);
        }
    }

    /*
     *************************************处理接受报文*****************************************
     */

    /*
     * 收集的航线信息插入数据库
     */
    public void trackInfoHandler(ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper) throws JsonProcessingException {
        int id = wrapper.getProtocolType1_3().getAddressProp();
        char serialNum = wrapper.getProtocolType1_3().getSerialNum();
        log.info("来自编号"+id+"的流水号为"+(int)serialNum+"的采集信息！");

        int totalPckNum = wrapper.getTotalPckNum();
        int pckNum = wrapper.getPckNum();
        UVAConnection connection = UVAServer.uvaConnections.get((int)(wrapper.getProtocolType1_3().getAddressProp()));
        if(connection.getMsgCache()==null){
            connection.setMsgCache(new ArrayList<>());
        }
        ArrayList<byte[]> picBytes = (ArrayList<byte[]>) connection.getMsgCache();
        picBytes.add(pckNum,wrapper.getProtocolType1_3().getMsgBody());
        if(picBytes.size()==totalPckNum){
            ArrayList<byte[]> tmp = new ArrayList<>(picBytes);
            picBytes.clear();
            List<Byte> bl = new ArrayList<>();
            for (byte[] b : tmp) {
                for (byte value : b) {
                    bl.add(value);
                }
            }
            int len = bl.size();
            byte[] picBytesArray = new byte[len];
            for(int i=0;i<len;i++){
                picBytesArray[i] = bl.get(i);
            }
            String trackJson = new String(picBytesArray, StandardCharsets.UTF_8);
            TrackInfo trackInfo = JacksonUtil.objectMapper.readValue(trackJson,TrackInfo.class);
            UVAServer.trackInfoService.create(trackInfo);

        }
    }
    /*
    * 无人机任务完成后修改其状态
    */
    public void taskFinHandler(ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper){
        byte id = wrapper.getProtocolType1_3().getAddressProp();
        log.info("编号"+id+"的无人机任务完成！");
        UVAConnection connection = UVAServer.uvaConnections.get((int)id);
        if(connection!=null){
            Aircraft aircraft = connection.getAircraft();
            if(aircraft!=null){
                aircraft.setAvailable(true);
            }
        }
    }
    //处理连接请求
    /*68 68    c0 58*/
    public void connectHandler(ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper){
        log.info("处理连接请求");
        byte id = wrapper.getProtocolType1_3().getAddressProp();
        byte[] msg = wrapper.getProtocolType1_3().getMsgBody();
        String uuid = new String(msg,StandardCharsets.UTF_8);
        //检查ID是否已经被使用
        if(UVAServer.uvaConnections.containsKey((int)id)){
            //如果已经使用，发送拒绝连接报文
            log.warn("已经使用的ID,拒绝连接！关闭socket。");
            sendConnectACK(ctx,id,(byte)0);
            ctx.channel().close();
            return;
        }
        if(UVAServer.disconnections.get((int) id)!=null){
            //如果重连队列中存在该ID
            //判断会话ID是否相同
            UVAConnection disconnection = UVAServer.disconnections.get((int)id);
            if(disconnection.getUUID().equals(uuid)){
                //说明是断线重连,把该会话转移到连接会话中，给无人机发送反馈消息
                try{
                    //更新channel
                    log.info("无人机"+id+"重连成功");
                    ctx.channel().attr(UVAServer.channel_key).set((int) (id));
                    disconnection.setChannel(ctx.channel());
                    UVAServer.uvaConnections.put((int)id,disconnection);
                    UVAServer.disconnections.remove((int)id);
                    sendConnectACK(ctx,id,(byte)1);
                }catch (Exception e){
                    sendConnectACK(ctx,id,(byte)0);
                }

            }else{
                //不是断线重连，视为新的连接，并且移除重连队列超时会话
                UVAServer.disconnections.remove((int)id);
                doConnect(id,uuid,ctx,wrapper);
            }
        }else{
            //否则，说明是新的连接
            doConnect(id,uuid,ctx,wrapper);
        }


    }
    public void doConnect(byte id,String uuid,ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper){
        try{
            //创建无人机连接实例
            UVAConnection connection = new UVAConnection();
            //创建对应的无人机实例并加入到无人机容器中,并且添加航线任务
            Aircraft aircraft = new Aircraft();
            //获取无人机信息
            log.info("无人机" + id + "请求连接");
            aircraft.setId(id);//无人机编号
            aircraft.setAvailable(true);//设置状态为可用
            Location location = new Location(wrapper.getProtocolType1_3().getLongitude(),
                    wrapper.getProtocolType1_3().getLatitude(), wrapper.getProtocolType1_3().getHeight());
            aircraft.setLocation(location);
            aircraft.setBattery(wrapper.getProtocolType1_3().getBattery());
            //将无人机加入到连接管理类中
            connection.setAircraft(aircraft);
            //将无人机连接会话UUID加入到连接管理类中
            connection.setUUID(uuid);
            //设置channel channel与无人机id绑定
            ctx.channel().attr(UVAServer.channel_key).set((int) (id));
            connection.setChannel(ctx.channel());
            //将无人机连接管理类加入到服务器连接管理表中
            UVAServer.uvaConnections.put((int) id, connection);
            sendConnectACK(ctx,id,(byte)1);
        }catch (Exception e){
            log.error(e.toString());

            sendConnectACK(ctx,id,(byte)0);
        }
    }
    //处理关闭请求
    /*68 68 12 01 00 00 1a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 90 59*/
    public void closeHandler(ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper){
        //将对应的无人机连接实例从无人机连接管理容器中移除
        byte id = wrapper.getProtocolType1_3().getAddressProp();
        if(UVAServer.uvaConnections.get((int)id)!=null) {
            UVAServer.uvaConnections.remove((int)id);
            log.info("无人机"+id+"主动正常断开连接,对应的连接已移除，服务器不再维护其连接");
        }
        //关闭对应的channel
        ctx.channel().close().addListener((ChannelFutureListener) channelFuture -> log.info("无人机"+id+"的channel关闭"));
    }
    //处理航线请求ACK
    public void routeInfoHandler(ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper) {
        log.info(wrapper.getProtocolType1_3().toString());
        byte id = wrapper.getProtocolType1_3().getAddressProp();
        byte ack = wrapper.getProtocolType1_3().getMsgBody()[0];
        switch (ack){
            case 1:
                //正确处理设置为不可用状态
                UVAServer.uvaConnections.get((int)id).getAircraft().setAvailable(false);
                UVAServer.uvaConnections.get((int)id).getAircraft().setFlyCause((byte)1);
                log.info("航线信息已被正确接收");
                break;
            case 2:
                UVAServer.uvaConnections.get((int)id).getAircraft().setAvailable(true);
                UVAServer.uvaConnections.get((int)id).getAircraft().setFlyCause((byte)2);
                log.info("电量不足！");
                break;
            case 3:
                UVAServer.uvaConnections.get((int)id).getAircraft().setAvailable(true);
                UVAServer.uvaConnections.get((int)id).getAircraft().setFlyCause((byte)3);
                log.info("GPS信号弱！");
                break;
            default:
                log.info("未定义的错误！");
                break;
        }
        //更新无人机位置
        locationHandler(ctx,wrapper);
    }
    //处理拍照请求ACK
    public void shotHandler(ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper){
        //更新无人机位置
        locationHandler(ctx,wrapper);
    }
    //处理预警请求ACK
    public void warnInfoHandler(ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper){
        byte id = wrapper.getProtocolType1_3().getAddressProp();
        byte warning = wrapper.getProtocolType1_3().getMsgBody()[0];
        LinkedList<Byte> warnings = UVAServer.uvaConnections.get((int)id).getAircraft().getWarnings();
        warnings.offer(warning);
        //更新无人机位置
        locationHandler(ctx,wrapper);
    }
//    //传输图片处理帧
//    public void pictureHandler(ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper){
//        log.info("接收图片");
//        int id = wrapper.getProtocolType1_3().getAddressProp();
//        //char serialNum = wrapper.getProtocolType1_3().getSerialNum();
//        int totalPckNum = wrapper.getTotalPckNum();
//        int pckNum = wrapper.getPckNum();
//        log.warn("--------------"+totalPckNum+"--------------"+pckNum);
////        if(!UVAServer.picCache.containsKey(serialNum)){
////            //还没存，初始化容器，并加入对应的位置
////            ArrayList<byte[]> picBytes = new ArrayList<>(totalPckNum+1);
////            UVAServer.picCache.put((int)serialNum,picBytes);
////        }
////        //已经存了对应的图片的包
////        ArrayList<byte[]> picBytes = UVAServer.picCache.get(serialNum);
////        picBytes.add(pckNum-1,wrapper.getProtocolType1_3().getMsgBody());//对方序号从1开始
////        //判断是否已经对应的所有包接收完毕
////        if(picBytes.size()==totalPckNum){
////            //接收完毕，交给其他线程拼接图片
////            try {
////                //图片解码
////                String imageName = UUID.randomUUID()+".jpg";
////                UVAServer.pictureService.bytes2Pic(serialNum,UVAServer.picCache,"D:\\pic\\"+imageName);//会使用线程池中的线程完成任务
////            } catch (IOException e) {
////                e.printStackTrace();
////            }
////        }
//        UVAConnection connection = UVAServer.uvaConnections.get((int)(wrapper.getProtocolType1_3().getAddressProp()));
//        if(connection.getMsgCache()==null){
//            connection.setMsgCache(new ArrayList<>());
//        }
//        ArrayList<byte[]> picBytes = (ArrayList<byte[]>) connection.getMsgCache();
//        picBytes.add(pckNum,wrapper.getProtocolType1_3().getMsgBody());
//        if(picBytes.size()==totalPckNum){
//            //把数据copy到其他地方，方便接收下一张图片数据，防止多线程并发问题
//            ArrayList<byte[]> tmp = new ArrayList<>(picBytes);
//            picBytes.clear();
//            try {
//                //图片解码
//                //String imageName = UUID.randomUUID()+".jpg";
//                UVAServer.pictureService.bytes2Pic(id,tmp);//会使用线程池中的线程完成任务
//            } catch (IOException e) {
//                //即使出现问题了，照片也不会再次拍，默认不再继续处理
//                log.error("接受来自无人机"+wrapper.getProtocolType1_3().getAddressProp()+"的图片发生异常");
//                e.printStackTrace();
//
//            }
//        }
//        //更新无人机位置
//        locationHandler(ctx,wrapper);
//
//    }
    //传输图片处理帧副本
    public void pictureHandler(ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper){
        log.info("接收图片");
        int id = wrapper.getProtocolType1_3().getAddressProp();
        //char serialNum = wrapper.getProtocolType1_3().getSerialNum();
        int totalPckNum = wrapper.getTotalPckNum();
        int pckNum = wrapper.getPckNum();
        log.warn("--------------"+totalPckNum+"--------------"+pckNum);
//        if(!UVAServer.picCache.containsKey(serialNum)){
//            //还没存，初始化容器，并加入对应的位置
//            ArrayList<byte[]> picBytes = new ArrayList<>(totalPckNum+1);
//            UVAServer.picCache.put((int)serialNum,picBytes);
//        }
//        //已经存了对应的图片的包
//        ArrayList<byte[]> picBytes = UVAServer.picCache.get(serialNum);
//        picBytes.add(pckNum-1,wrapper.getProtocolType1_3().getMsgBody());//对方序号从1开始
//        //判断是否已经对应的所有包接收完毕
//        if(picBytes.size()==totalPckNum){
//            //接收完毕，交给其他线程拼接图片
//            try {
//                //图片解码
//                String imageName = UUID.randomUUID()+".jpg";
//                UVAServer.pictureService.bytes2Pic(serialNum,UVAServer.picCache,"D:\\pic\\"+imageName);//会使用线程池中的线程完成任务
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
        UVAConnection connection = UVAServer.uvaConnections.get((int)(wrapper.getProtocolType1_3().getAddressProp()));
        if(connection.getMsgCache()==null){
            connection.setMsgCache(new ArrayList<>());
        }
        ArrayList<byte[]> picBytes = (ArrayList<byte[]>) connection.getMsgCache();
        byte[] data = wrapper.getProtocolType1_3().getMsgBody();
        if(pckNum==0){
            //第一包
            byte detect = data[0];
            connection.setPicDetect((int)detect);
            byte[] longitudeBytes = new byte[8];
            System.arraycopy(data, 1, longitudeBytes, 0, 8);
            byte[] latitudeBytes = new byte[8];
            System.arraycopy(data,9,latitudeBytes,0,8);
            connection.setPicLongitude(ByteUtil.getDouble(longitudeBytes));
            connection.setPicLatitude(ByteUtil.getDouble(latitudeBytes));
            byte[] picData = new byte[data.length-17];
            System.arraycopy(data,17,picData,0,picData.length);
            picBytes.add(pckNum,picData);
        }else{
            picBytes.add(pckNum,data);
        }
        if(picBytes.size()==totalPckNum){
            //把数据copy到其他地方，方便接收下一张图片数据，防止多线程并发问题
            ArrayList<byte[]> tmp = new ArrayList<>(picBytes);
            picBytes.clear();
            try {
                //图片解码
                //String imageName = UUID.randomUUID()+".jpg";
                UVAServer.pictureService.bytes2Pic(id,tmp,connection.getPicDetect(),
                        connection.getPicLongitude(),connection.getPicLatitude());//会使用线程池中的线程完成任务
            } catch (IOException e) {
                //即使出现问题了，照片也不会再次拍，默认不再继续处理
                log.error("接受来自无人机"+wrapper.getProtocolType1_3().getAddressProp()+"的图片发生异常");
                e.printStackTrace();

            }
        }
        //更新无人机位置
        //locationHandler(ctx,wrapper);

    }

    //无人机位置更新,电量更新，同时作为心跳包
    public void locationHandler(ChannelHandlerContext ctx,UVAMessageProtocolWrapper wrapper){
        byte id = wrapper.getProtocolType1_3().getAddressProp();
        Aircraft aircraft = UVAServer.uvaConnections.get((int)id).getAircraft();
        aircraft.getLocation().setLongitude(wrapper.getProtocolType1_3().getLongitude());
        aircraft.getLocation().setLatitude(wrapper.getProtocolType1_3().getLatitude());
        aircraft.getLocation().setHeight(wrapper.getProtocolType1_3().getHeight());
        aircraft.setBattery(wrapper.getProtocolType1_3().getBattery());

        sendLocationInfoACK(ctx,id);

    }

    /**
     * ********************************************发送报文*******************************************
     */

    //发送位置信息确认消息，也是心跳包
    public void sendLocationInfoACK(ChannelHandlerContext ctx, byte id){
        byte div = 0x00;
        byte op = ServerOPType.OP_SEND_LOCATION_INFO_ACK;
        byte controlProp = packControlProp(div,op);
        byte[] divs = {0,0,0,0};
        byte[] msg = {};
        UVAMessageProtocolType1_3 locationInfoACKMsg = new UVAMessageProtocolType1_3.Builder()
                .setControlProp(controlProp)
                .setDivs(divs).setMsgBodyLen((short)msg.length)
                .setMsgBody(msg)
                .setSerialNum(UVAServer.uvaConnections.get((int)id).getSerialNum())
                .build();
        UVAMessageProtocolWrapper locationInfoACKMsgWrapper = new UVAMessageProtocolWrapper(locationInfoACKMsg);
        short crcCheckNum = CRC16Util.getCRC(locationInfoACKMsgWrapper.protocol2Array0());
        locationInfoACKMsg.setCrcCheckNum(crcCheckNum);
        ctx.writeAndFlush(locationInfoACKMsg);
    }
    //更改控制模式
    public void switchControlMode(ChannelHandlerContext ctx, byte id, byte mode){
        byte div = 0x00;
        byte op = ServerOPType.OP_SWITCH_CONTROL_MODE;
        byte controlProp = packControlProp(div,op);
        byte[] divs = {0,0,0,0};
        byte[] msg = {mode};
        UVAMessageProtocolType1_3 switchControlModeMsg = new UVAMessageProtocolType1_3.Builder()
                .setControlProp(controlProp)
                .setDivs(divs).setMsgBodyLen((short) msg.length)
                .setMsgBody(msg)
                .setSerialNum(UVAServer.uvaConnections.get((int)id).getSerialNum())
                .build();
        UVAMessageProtocolWrapper switchControlModeMsgWrapper = new UVAMessageProtocolWrapper(switchControlModeMsg);
        short crcCheckNum = CRC16Util.getCRC(switchControlModeMsgWrapper.protocol2Array0());
        switchControlModeMsg.setCrcCheckNum(crcCheckNum);
        ctx.writeAndFlush(switchControlModeMsg);
    }

    //发送确认信息
    public void sendConnectACK(ChannelHandlerContext ctx, byte id, byte ack){
        if(ack==1){
            log.info("向无人机"+id+"发送连接确认");
        }else {
            log.info("拒绝无人机"+id+"的连接请求");
        }

        //发送连接ACK报文
        byte div = 0x00;
        byte op = ServerOPType.OP_CONNECTION_ACCEPT_OR_ABORT;
        byte controlProp = packControlProp(div,op);
        byte[] divs = {0,0,0,0};
        byte[] msg = {ack};
        UVAMessageProtocolType1_3 connectMsg = new UVAMessageProtocolType1_3.Builder()
                .setControlProp(controlProp)
                .setDivs(divs)
                .setMsgBodyLen((short) msg.length)
                .setMsgBody(msg)
                .setSerialNum(UVAServer.uvaConnections.get((int)id).getSerialNum())
                .build();
        UVAMessageProtocolWrapper connectMsgWrapper = new UVAMessageProtocolWrapper(connectMsg);
        short crcCheckNum = CRC16Util.getCRC(connectMsgWrapper.protocol2Array0());
        connectMsg.setCrcCheckNum(crcCheckNum);
        ctx.writeAndFlush(connectMsg);
    }
    //发送关闭连接信息
    public void sendFIN(ChannelHandlerContext ctx,byte id){
        log.info("向无人机"+id+"发送关闭请求");
        byte div = 0x00;
        byte op = ServerOPType.OP_CLOSE_CONNECTION;
        byte controlProp = packControlProp(div,op);
        byte[] divs={0,0,0,0};
        byte[] msg = {};
        UVAMessageProtocolType1_3 closeMsg = new UVAMessageProtocolType1_3.Builder()
                .setControlProp(controlProp)
                .setDivs(divs)
                .setMsgBodyLen((short) msg.length)
                .setMsgBody(msg)
                .setSerialNum(UVAServer.uvaConnections.get((int)id).getSerialNum())
                .build();
        UVAMessageProtocolWrapper closeMsgWrapper = new UVAMessageProtocolWrapper(closeMsg);
        short crcCheckNum = CRC16Util.getCRC(closeMsgWrapper.protocol2Array0());
        closeMsg.setCrcCheckNum(crcCheckNum);
        ctx.writeAndFlush(closeMsg);
    }
    //发送航线信息
    public void sendRouteInfo(ChannelHandlerContext ctx,byte id) throws JsonProcessingException {
        log.info("向无人机"+id+"发送航线信息");
        byte div = 0x00;
        byte op = ServerOPType.OP_SEND_ROUTE_INFO;
        byte controlProp = packControlProp(div,op);
        byte[] divs = {0,0,0,0};
        Aircraft aircraft = UVAServer.uvaConnections.get((int)id).getAircraft();
//        List<Location> route =  aircraft.getRoute();
        FlightTask task = aircraft.getTask();
        byte[] msg = JacksonUtil.objectMapper.writeValueAsString(task.getRoute()).getBytes(StandardCharsets.UTF_8);
        UVAMessageProtocolType1_3 routeMsg = new UVAMessageProtocolType1_3.Builder()
                .setControlProp(controlProp)
                .setDivs(divs)
                .setMsgBodyLen((short) msg.length)
                .setMsgBody(msg)
                .setSerialNum(UVAServer.uvaConnections.get((int)id).getSerialNum())
                .build();
        UVAMessageProtocolWrapper wrapper = new UVAMessageProtocolWrapper(routeMsg);
        routeMsg.setCrcCheckNum(CRC16Util.getCRC(wrapper.protocol2Array0()));
        ctx.writeAndFlush(routeMsg);
    }


    //发送请求拍照信息
    public void requestShot(ChannelHandlerContext ctx,byte id,int camera_id){
        log.info("向无人机"+id+"发送拍照请求");
        byte div = 0x00;
        byte controlProp = packControlProp(div, ServerOPType.OP_REQUEST_SHOT);
        byte[] divs = {0,0,0,0};
        byte[] msg = {(byte) camera_id};
        UVAMessageProtocolType1_3 requestShotMsg = new UVAMessageProtocolType1_3.Builder()
                .setControlProp(controlProp)
                .setDivs(divs)
                .setMsgBodyLen((short) msg.length)
                .setMsgBody(msg)
                .setSerialNum(UVAServer.uvaConnections.get((int)id).getSerialNum())
                .build();
        UVAMessageProtocolWrapper wrapper = new UVAMessageProtocolWrapper(requestShotMsg);
        requestShotMsg.setCrcCheckNum(CRC16Util.getCRC(wrapper.protocol2Array0()));
        ctx.writeAndFlush(requestShotMsg);
    }
    //发送预警信息
    public void sentWarnInfo(ChannelHandlerContext ctx, byte id, byte warnType){
        log.info("向无人机"+id+"发送预警："+warnType);
        byte div = 0x00;
        byte controlProp = packControlProp(div, ServerOPType.OP_SEND_WARNING_INFO);
        byte[] divs = {0,0,0,0};
        byte[] msg = { warnType};
        UVAMessageProtocolType1_3 warnMsg = new UVAMessageProtocolType1_3.Builder()
                .setControlProp(controlProp)
                .setDivs(divs)
                .setMsgBodyLen((short) msg.length)
                .setMsgBody(msg)
                .setSerialNum(UVAServer.uvaConnections.get((int)id).getSerialNum())
                .build();
        UVAMessageProtocolWrapper wrapper = new UVAMessageProtocolWrapper(warnMsg);
        warnMsg.setCrcCheckNum(CRC16Util.getCRC(wrapper.protocol2Array0()));
        ctx.writeAndFlush(warnMsg);
    }
    //发送飞行控制指令 command还未定义
    public void sendControlCommand(ChannelHandlerContext ctx,byte id,ControlCommand command){
        log.info("向无人机"+id+"发送控制命令");
        byte div = 0x00;
        byte controlProp = packControlProp(div, ServerOPType.OP_SEND_CONTROL_COMMAND);
        byte[] divs = {0,0,0,0};
        byte[] msg = command.command2bytes();
        UVAMessageProtocolType1_3 commandMsg = new UVAMessageProtocolType1_3.Builder()
                .setControlProp(controlProp)
                .setDivs(divs)
                .setMsgBodyLen((short) msg.length)
                .setMsgBody(msg)
                .setSerialNum(UVAServer.uvaConnections.get((int)id).getSerialNum())
                .build();
        UVAMessageProtocolWrapper wrapper = new UVAMessageProtocolWrapper(commandMsg);
        commandMsg.setCrcCheckNum(CRC16Util.getCRC(wrapper.protocol2Array0()));
        ctx.writeAndFlush(commandMsg);
    }
    /********************************辅助函数*****************************************/
    /**
     * @Description "封装控制域字段"
     * @Param
     * @Return
     * @Author chengeng
     * @Date 2021/12/2 11:05
     **/
    private byte packControlProp(byte div, byte op){
        byte controlProp = 0x00;
        controlProp = (byte) ((UVAServer.DIRECTION <<7)+(div<<6)+op);
        return controlProp;
    }
}
